package com.youlai.boot.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.system.converter.SpotTicketConverter;
import com.youlai.boot.system.enums.DictCodeEnum;
import com.youlai.boot.system.mapper.SpotTicketMapper;
import com.youlai.boot.system.model.entity.*;
import com.youlai.boot.system.model.form.SpotTicketForm;
import com.youlai.boot.system.model.query.SpotTicketQuery;
import com.youlai.boot.system.model.vo.SpotTicketExcelVO;
import com.youlai.boot.system.model.vo.SpotTicketVO;
import com.youlai.boot.system.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 预售票数据服务实现类
 *
 * @author 李文兵
 * @since 2025-06-29 17:29
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SpotTicketServiceImpl extends ServiceImpl<SpotTicketMapper, SpotTicket> implements SpotTicketService {

    private final SpotTicketConverter spotTicketConverter;

    private final SpotTravelService spotTravelService;

    private final SpotCategoryService spotCategoryService;

    private final DeptService deptService;

    private final DictDataService dictDataService;

    private final SpotCountService spotCountService;

    /**
     * 获取预售票数据分页列表
     *
     * @param queryParams 查询参数
     * @return {@link IPage<SpotTicketVO>} 预售票数据分页列表
     */
    @Override
    public IPage<SpotTicketVO> getSpotTicketPage(SpotTicketQuery queryParams) {
        Page<SpotTicketVO> pageVO = this.baseMapper.getSpotTicketPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams
        );
        return pageVO;
    }

    /**
     * 获取预售票数据表单数据
     *
     * @param id 预售票数据ID
     * @return
     */
    @Override
    public SpotTicketForm getSpotTicketFormData(Long id) {
        return this.baseMapper.getSpotTicketFormData(id);
    }

    /**
     * 新增预售票数据
     *
     * @param formData 预售票数据表单对象
     * @return
     */
    @Override
    public boolean saveSpotTicket(SpotTicketForm formData) {
        SpotTicket entity = spotTicketConverter.toEntity(formData);
        fieldFill(entity);
        return this.save(entity);
    }

    public void fieldFill(SpotTicket entity) {
        Long userId = SecurityUtils.getUserId();
        LocalDateTime now = LocalDateTime.now();
        if (entity.getId() == null) {
            entity.setCreateBy(userId);
            entity.setCreateTime(now);
            entity.setUpdateBy(userId);
            entity.setUpdateTime(now);
        } else {
            entity.setUpdateBy(userId);
            entity.setUpdateTime(now);
        }
    }

    /**
     * 更新预售票数据
     *
     * @param id       预售票数据ID
     * @param formData 预售票数据表单对象
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateSpotTicket(Long id, SpotTicketForm formData, boolean fillNum) {
        SpotTicket spotTicket = this.getById(id);
        if (spotTicket == null) {
            throw new BusinessException("预售票数据不存在，操作失败！");
        }
        if (spotTicket.getAuditResult() == 2) {
            throw new BusinessException("已审核通过，请勿再次发起审核！");
        }

        SpotTicket entity = spotTicketConverter.toEntity(formData);
        fieldFill(entity);
        boolean update = this.updateById(entity);

        // 更新成功且是审核通过的接口
        if (update && fillNum) {
            SpotTravel spotTravel = spotTravelService.getSpotTravel(formData.getDeptId(), formData.getCategoryId());
            if (spotTravel != null) {
                spotTravel.setNum(spotTravel.getNum() + formData.getNum());

            } else {
                spotTravel = new SpotTravel();
                spotTravel.setCategoryId(formData.getCategoryId());
                spotTravel.setDeptId(formData.getDeptId());
                spotTravel.setNum(formData.getNum());
            }
            Long userId = SecurityUtils.getUserId();
            fieldFill(spotTravel, userId);
            spotTravelService.saveOrUpdate(spotTravel);

            //增加当前预售记录
            LocalDateTime now = LocalDateTime.now();
            SpotCount spotCount = new SpotCount();
            spotCount.setDeptId(entity.getDeptId());
            spotCount.setDeptName(entity.getDeptName());
            spotCount.setCategoryId(entity.getCategoryId());
            spotCount.setCategoryName(entity.getCategoryName());
            spotCount.setUserId(entity.getRecordBy());

            spotCount.setOperateType(2);
            spotCount.setNum(entity.getNum());
            spotCount.setOperateTime(entity.getRecordTime());

            spotCount.setCreateBy(entity.getCreateBy());
            spotCount.setCreateTime(now);
            spotCount.setUpdateBy(entity.getCreateBy());
            spotCount.setUpdateTime(now);
            spotCountService.save(spotCount);
        }
        return update;
    }

    public void fieldFill(SpotTravel entity, Long userId) {
        LocalDateTime now = LocalDateTime.now();
        if (entity.getId() == null) {
            entity.setCreateBy(userId);
            entity.setCreateTime(now);
            entity.setUpdateBy(userId);
            entity.setUpdateTime(now);
        } else {
            entity.setUpdateBy(userId);
            entity.setUpdateTime(now);
        }
    }

    /**
     * 删除预售票数据
     *
     * @param ids 预售票数据ID，多个以英文逗号(,)分割
     * @return
     */
    @Override
    public boolean deleteSpotTickets(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的预售票数据数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        LambdaQueryWrapper<SpotTicket> lqw = new LambdaQueryWrapper<>();
        //查询审核中,审核通过的
        lqw.in(SpotTicket::getAuditResult, Arrays.asList(1));
        lqw.in(SpotTicket::getId, idList);

        List<SpotTicket> list = this.list(lqw);
        if (CollectionUtil.isNotEmpty(list)) {
            throw new BusinessException("删除的数据中存在审核中数据，请刷新页面后重新操作！");
        }

        return this.removeByIds(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reportSpotTickets(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的预售票数据数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        LambdaQueryWrapper<SpotTicket> lqw = new LambdaQueryWrapper<>();
        //查询审核中,审核通过的
        lqw.in(SpotTicket::getAuditResult, Arrays.asList(1, 2));
        lqw.in(SpotTicket::getId, idList);

        List<SpotTicket> list = this.list(lqw);
        if (CollectionUtil.isNotEmpty(list)) {
            throw new BusinessException("发起审核的数据中存在待审核或已审核数据，请刷新页面后重新操作！");
        }
        UpdateWrapper<SpotTicket> up = new UpdateWrapper<>();
        up.in("id", idList);
        up.set("audit_result", 1);
        this.update(up);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean refundSpotTickets(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "批量退回的预售票数据数据为空");
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();

        //将之前的票退回  无法退回报错
        List<SpotTicket> ticketList = baseMapper.selectBatchIds(idList);
        if (CollectionUtil.isNotEmpty(ticketList)) {

            List<SpotTravel> spotTravelList = new ArrayList<>();
            List<SpotCount> spotCountList = new ArrayList<>();

            log.info("{}批量退回，修改旅行社的预售票数量", SecurityUtils.getUsername());
            //修改旅行社的预售票数量SpotTravel
            Long userId = SecurityUtils.getUserId();
            ticketList.stream().forEach(ticket -> {
                SpotTravel spotTravel = spotTravelService.getSpotTravel(ticket.getDeptId(), ticket.getCategoryId());
                if (spotTravel != null) {
                    if (spotTravel.getNum() >= ticket.getNum()) {
                        spotTravel.setNum(spotTravel.getNum() - ticket.getNum());
                        fieldFill(spotTravel, userId);
                    } else {
                        String message = spotTravel.getDeptName() + "没有足够的" + spotTravel.getCategoryName() + "预售票进行退回，当前剩余" + spotTravel.getNum() + "，操作失败！";
                        throw new BusinessException(message);
                    }
                } else {
                    SpotCategory spotCategory = spotCategoryService.getCategoryById(ticket.getCategoryId());
                    Dept dept = deptService.getDeptById(ticket.getDeptId());
                    throw new BusinessException(dept.getName() + "没有" + spotCategory.getName() + "的余票！请联系相关人员处理！");
                }
                spotTravelList.add(spotTravel);

                //增加当前出票记录
                LocalDateTime now = LocalDateTime.now();
                SpotCount spotCount = new SpotCount();
                spotCount.setDeptId(ticket.getDeptId());
                spotCount.setDeptName(ticket.getDeptName());
                spotCount.setCategoryId(ticket.getCategoryId());
                spotCount.setCategoryName(ticket.getCategoryName());
                spotCount.setUserId(ticket.getRecordBy());

                spotCount.setOperateType(1);
                spotCount.setNum(ticket.getNum());
                spotCount.setOperateTime(ticket.getRecordTime());

                spotCount.setCreateBy(ticket.getCreateBy());
                spotCount.setCreateTime(now);
                spotCount.setUpdateBy(ticket.getCreateBy());
                spotCount.setUpdateTime(now);
                spotCountList.add(spotCount);

            });
            if (CollectionUtil.isNotEmpty(spotTravelList)) {
                spotTravelService.updateBatchById(spotTravelList);
            }
            if (CollectionUtil.isNotEmpty(spotCountList)) {
                spotCountService.saveBatch(spotCountList);
            }
        } else {
            throw new BusinessException("预售票数据不存在，操作失败！");
        }

        UpdateWrapper<SpotTicket> up = new UpdateWrapper<>();
        up.in("id", idList);
        up.set("audit_result", 0);
        up.set("audit_time", null);
        up.set("audit_by", null);
        up.set("remark", "");
        this.update(up);
        log.info("{}批量退回，修改旅行社的预售票数量成功", SecurityUtils.getUsername());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditSpotTickets(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "批量审核的预售票数据数据为空");
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();

        List<SpotTicket> ticketList = baseMapper.selectBatchIds(idList);
        if (CollectionUtil.isNotEmpty(ticketList)) {
            SpotTicket spotTicket = ticketList.stream().filter(ticket -> ticket.getAuditResult() == 2).findFirst().orElse(null);
            if (spotTicket != null) {
                throw new BusinessException("已审核通过，请勿再次发起审核！");
            }
            log.info("{}审核通过，修改旅行社的预售票数量", SecurityUtils.getUsername());
            //修改旅行社的预售票数量SpotTravel
            Long userId = SecurityUtils.getUserId();
            ticketList.stream().forEach(ticket -> {
                SpotTravel spotTravel = spotTravelService.getSpotTravel(ticket.getDeptId(), ticket.getCategoryId());
                if (spotTravel != null) {
                    spotTravel.setNum(spotTravel.getNum() + ticket.getNum());
                } else {
                    spotTravel = new SpotTravel();
                    spotTravel.setCategoryId(ticket.getCategoryId());
                    spotTravel.setDeptId(ticket.getDeptId());
                    spotTravel.setNum(ticket.getNum());
                }
                fieldFill(spotTravel, userId);
                spotTravelService.saveOrUpdate(spotTravel);

                //增加当前预售记录
                LocalDateTime now = LocalDateTime.now();
                SpotCount spotCount = new SpotCount();
                spotCount.setDeptId(ticket.getDeptId());
                spotCount.setDeptName(ticket.getDeptName());
                spotCount.setCategoryId(ticket.getCategoryId());
                spotCount.setCategoryName(ticket.getCategoryName());
                spotCount.setUserId(ticket.getRecordBy());

                spotCount.setOperateType(2);
                spotCount.setNum(ticket.getNum());
                spotCount.setOperateTime(ticket.getRecordTime());

                spotCount.setCreateBy(ticket.getCreateBy());
                spotCount.setCreateTime(now);
                spotCount.setUpdateBy(ticket.getCreateBy());
                spotCount.setUpdateTime(now);
                spotCountService.save(spotCount);
            });
        } else {
            throw new BusinessException("预售票数据不存在，操作失败！");
        }

        UpdateWrapper<SpotTicket> up = new UpdateWrapper<>();
        up.in("id", idList);
        up.set("audit_result", 2);
        up.set("audit_time", LocalDateTime.now());
        up.set("audit_by", SecurityUtils.getUserId());
        up.set("remark", "审核通过");
        this.update(up);
        return true;
    }

    /**
     * @param queryParams
     * @return
     */
    @Override
    public List<SpotTicketExcelVO> export(SpotTicketQuery queryParams) {
        List<SpotTicketExcelVO> list = this.baseMapper.exportList(queryParams);
        if (CollUtil.isNotEmpty(list)) {

            //获取权限的字典数据
            List<DictData> dictList = dictDataService.list(new LambdaQueryWrapper<DictData>()
                    .eq(DictData::getDictCode, DictCodeEnum.AUDITRESULT.getValue()));
            Map<String, List<DictData>> dictMap = dictList.stream().collect(Collectors.groupingBy(DictData::getDictCode));

            AtomicInteger index = new AtomicInteger(1);
            list.forEach(item -> {

                List<DictData> landTypeDictData = dictMap.get(DictCodeEnum.AUDITRESULT.getValue());
                if (CollUtil.isNotEmpty(landTypeDictData)) {
                    DictData dictData = landTypeDictData.stream()
                            .filter(data -> data.getValue().equals(String.valueOf(item.getAuditResult())))
                            .findFirst().orElse(null);
                    item.setAuditResult(dictData != null ? dictData.getLabel() : "");
                }

                item.setSn(String.valueOf(index.getAndIncrement()));
            });
        }
        return list;
    }

    @Override
    public List<SpotTicketForm> getCount(SpotTicketQuery queryParams) {
        return baseMapper.getCount(queryParams);
    }
}
